#include <iostream>
#include <cstdlib>
#include <sys/types.h>
#include <unistd.h>
#include <ctime>
#include <vector>
#include <string>
#include "BlockQueue.hpp"
#include "Task.hpp"


class TaskData
{
public:
    TaskData()
    {}
    TaskData(BlockQueue<Task> *bq, const std::string& name)
        :_bq(bq), _name(name)
    {}
    BlockQueue<Task> *_bq;
    std::string _name;
};

const std::string opers = "+-*[/{%]0";
void *Productor(void *args)
{
    TaskData* td = static_cast<TaskData* >(args);
    while(true)
    {
        sleep(1);
        int data_x = rand() % 10; 
        usleep(1000);
        int data_y = rand() % 10; 
        char op = opers[rand() % opers.size()];
        Task t(data_x, data_y, op);
        std::cout << td->_name <<": "<< t.PrintTask() << std::endl;
        td->_bq->Push(t);
    }
}

void *Consumer(void *args)
{
    TaskData* td = static_cast<TaskData* >(args);
    while(true)
    {
        // sleep(1);
        Task t;
        td->_bq->Pop(&t);
        t();
        std::cout << td->_name << t.PrintResult() << std::endl;
    }
}

int main()
{
    srand(time(nullptr) ^ pthread_self() ^ getpid());
    pthread_t p1[3], p2[2];

    BlockQueue<Task> *bq = new BlockQueue<Task>();
    TaskData td1(bq, "Productor-1");
    pthread_create(&p1[0], nullptr, Productor, (void *)&td1);

    TaskData td2(bq, "Productor-2");
    pthread_create(&p1[1], nullptr, Consumer, (void *)&td2);

    TaskData td3(bq, "Productor-3");
    pthread_create(&p1[2], nullptr, Consumer, (void *)&td3);

    TaskData td4(bq, "Consumer-1");
    pthread_create(&p2[0], nullptr, Consumer, (void *)&td4);

    TaskData td5(bq, "Consumer-2");
    pthread_create(&p2[1], nullptr, Consumer, (void *)&td5);

    pthread_join(p1[0], nullptr);
    pthread_join(p1[1], nullptr);
    pthread_join(p1[2], nullptr);
    pthread_join(p2[0], nullptr);
    pthread_join(p2[1], nullptr);
    return 0;
}